package com.zzzy.server.security;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zzzy.common.exception.WarningException;
import com.zzzy.common.util.AssertUtil;
import com.zzzy.common.util.CglibBeanCopierUtil;
import com.zzzy.framework.common.enums.sys.DataScopeEnum;
import com.zzzy.framework.common.enums.sys.UserStatusEnum;
import com.zzzy.framework.common.util.SecurityUtils;
import com.zzzy.framework.dto.DataPermissionDto;
import com.zzzy.framework.dto.LoginUser;
import com.zzzy.sys.cache.LoginErrorCountCache;
import com.zzzy.server.common.util.AuthenticationContextHolder;
import com.zzzy.sys.dao.entity.Menu;
import com.zzzy.sys.dao.entity.User;
import com.zzzy.sys.service.MenuService;
import com.zzzy.sys.service.RoleService;
import com.zzzy.sys.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Description: 用户验证处理
 *
 * @author fc
 * @date 2024/4/12
 */
@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Resource
    private UserService userService;
    @Resource
    private LoginErrorCountCache loginErrorCountCache;
    @Resource
    private MenuService menuService;
    @Resource
    private RoleService roleService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, username));
        AssertUtil.nonNull(user, "登录用户不存在");
        AssertUtil.isEquals(user.getStatus(), UserStatusEnum.ENABLE.getValue(), "登录用户状态异常，请联系管理员");
        validatePassword(user.getPassword());
        return createLoginUser(user);
    }

    public UserDetails createLoginUser(User user) {
        LoginUser loginUser = CglibBeanCopierUtil.copy(user, LoginUser.class);
        if (loginUser.isAdmin()){
            List<Menu> menuList = menuService.getAdminMenu();
            Set<String> permissionSet = menuList.stream().map(Menu::getPerms).filter(StringUtils::isNotBlank).collect(Collectors.toSet());
            loginUser.setPermissions(permissionSet);
            loginUser.setDataPermissionDto(new DataPermissionDto(DataScopeEnum.ALL.getValue()));
        } else {
            List<Menu> menuList = menuService.getMenuListByUserId(user.getId());
            Set<String> permissionSet = menuList.stream().map(Menu::getPerms).filter(StringUtils::isNotBlank).collect(Collectors.toSet());
            AssertUtil.isNotEmpty(permissionSet, "当前用户无权限，请联系管理员分配用户权限");
            loginUser.setPermissions(permissionSet);
            DataPermissionDto dataPermissionDto = roleService.getDataPermissionDto(user.getId());
            loginUser.setDataPermissionDto(dataPermissionDto);
        }
        return loginUser;
    }


    public void validatePassword(String correctPassword) {
        Authentication authentication = AuthenticationContextHolder.getContext();
        String username = authentication.getName();
        String password = authentication.getCredentials().toString();

        Integer errorCount = loginErrorCountCache.getCache(username);
        if (errorCount >= 10) {
            throw new WarningException("您输入的密码错误次数已达"+ 10 +"次，该账号将被锁定1小时。请稍后再尝试重新登录。");
        }

        if (!SecurityUtils.matchesPassword(password, correctPassword)) {
            loginErrorCountCache.putCache(username, ++errorCount);
            throw new WarningException("密码错误，当前错误 "+ errorCount +" 次，错误10次后，账号将锁定1小时。");
        } else {
            loginErrorCountCache.removeCache(username);
        }
    }
}
